# -*- encoding: utf-8 -*-
"""
@File    : auto_test_v1.1.py
@Time    : 2020/1/10 11:58
@Author  : Doris
"""

# 拆分方法
import configparser
import os
import sys
import time
import xml.etree.ElementTree as ET

# 配置文件名
settingsFile = "settings_v1.1.ini"

# 全局变量，api计数
x = 1

JMETER_PATH = 'jmeter'
# 服务器使用
# JMETER_PATH = '/apps/jmeter/apache-jmeter-5.2.1/bin/jmeter'

print("sys.path[0]:", sys.path[0])
print ("文件地址(含文件名）__file__:", __file__)
print("文件名os.path.basename(__file__)：",os.path.basename(__file__))
# 效果等同于__file__,但是斜杠倒过来，这个是windows的反斜杠
print("os.path.abspath(os.path.basename(__file__))：",os.path.abspath(os.path.basename(__file__)))
print("文件所在目录os.path.abspath("")：", os.path.abspath(""))

# 当前文件路径
# CURRENT_PATH = os.getcwd ()
# CURRENT_PATH = '/opt/jmeter/Version1.1'
CURRENT_PATH = sys.path[0]


#  方法：获取当前时间，用于命名
# 格式'20150708_085159-'
def getDateTime():
    return time.strftime (r'%Y%m%d_%H%M%S-', time.localtime (time.time ()))


# 获取当前时间用于生成报告文件夹
begin = getDateTime ()
print ("==>>当前时间：", begin)

# jmx生成路径
JMX_API_PATH = CURRENT_PATH + "/api_jmx/"
print ("==>>jmx生成路径：", JMX_API_PATH)

# 测试报告存放地址(需要目录存在）
REPORT_PATH = CURRENT_PATH + "/report/" + begin + "report/"
print ("==>>测试报告存放地址：", REPORT_PATH)

# 测试结果地址(需要目录存在）
RESULT_PATH = CURRENT_PATH + "/result/" + begin + "result/"
print ("==>>测试结果地址：", RESULT_PATH)

html_report_list = []
jmx_file_name_list = []

# 报告汇总v1.0，拼html语句
# 之后改bs4啦
head = '<!DOCTYPE html><html lang="en"><head><title>报告汇总主页</title></head><body><div ' \
       'name="reportTable" style="text-align: center"><table border="1" style="margin: auto"> '
end = '</table></div></body></html>'


# 方法：检查路径是否存在
# 不存在就新建文件夹
def checkPath(path):
    if os.path.exists (path):
        pass
    else:
        os.makedirs (path)


# 方法：读取并从模板中编辑生成JMX文件
def editJMX(jmxFile, apiName, ip, port, path, param, loops, num_threads, ramp_time):
    tree = ET.parse (jmxFile)
    root = tree.getroot ()  # Reading the file from disk

    # 获取要修改的标签
    s_loop = root.find (".//*[@name='LoopController.loops']")
    s_num_threads = root.find (".//*[@name='ThreadGroup.num_threads']")
    s_ramp_time = root.find (".//*[@name='ThreadGroup.ramp_time']")
    s_domain = root.find (".//*[@name='HTTPSampler.domain']")
    s_port = root.find (".//*[@name='HTTPSampler.port']")
    s_path = root.find (".//*[@name='HTTPSampler.path']")
    s_param = root.find (".//*[@name='Argument.value']")

    # 修改标签内容
    s_domain.text = str (ip)
    s_port.text = str (port)
    s_path.text = str (path)
    s_param.text = str (param)
    s_loop.text = str (loops)
    s_num_threads.text = str (num_threads)
    s_ramp_time.text = str (ramp_time)
    print ("==>>jmx文件地址：", JMX_API_PATH + apiName + '.jmx')
    tree.write (JMX_API_PATH + apiName + '.jmx')  # 只能用加号，逗号出错


# 方法：拆分一行api数据
# 主机/路径/参数
def splitData(apiData):
    api_name, host, path, param = apiData.split ('$', 3)  # 以$分割3次
    ip, port = host.split (':', 1)  # 以:分割一次
    return api_name, ip, port, path, param


# 方法：执行命令行运行jmx非GUI界面脚本测试
def excuteJMX(jmxPath):
    # 执行生成api文件夹下的api.jmx
    # 遍历api
    # for n in range (1, x):
    print("======================遍历jmx文件目录内容开始======================")
    for root, dirs, files in os.walk (jmxPath):
        print ("root:", root)
        print ("dirs:", dirs)
        print ("files", files)
        break

    print("======================执行jmx并生成报告开始======================")
    for file in files:
        now = getDateTime ()  # 获取当前时间
        api_name, file_type = file.split (".")  # api的名字,分割获取
        print ("api的名字：", api_name)
        name = now + api_name  # 报告结果名
        # 执行jmx
        run = JMETER_PATH + " -n -t " + JMX_API_PATH + api_name + ".jmx"
        # 生成并存储测试结果和报告
        generate_result = " -l" + RESULT_PATH + name + "_result.jsl -e -o " + REPORT_PATH + name
        cmd = run + generate_result
        os.system (cmd)


# 方法：生成报告汇总html页面
def createHtml(htmlFile, begin_time):
    print ("报告文件夹是：", REPORT_PATH)
    # 1.获取报告文件夹内容,目录名
    for root, dirs, files in os.walk (REPORT_PATH):
        break  # 获取第一子目录列表
    print (dirs)

    # 2.整理html内容
    # 2.1 设置标题<th>
    title = ['执行时间', '接口jmx文件', '响应结果', '报告详情']
    # 标题行
    th_str = '<tr name="title">'
    for x in title:
        th_str = th_str + '<th>' + x + '</th>'
    else:
        th_str = th_str + '</tr>'

    # 文件夹列表长度（个数）
    length = len (dirs)
    print ("==>>文件夹长度（个数）：", length, "\n================")

    # ==>>那么有问题了，同一个文件夹，把之前的报告也读了，要处理
    # 每次都新建文件夹，以测试时间为文件名，包含这次所有报告

    # 2.2 设置每个api报告链接内容<td>
    # 构建报告链接,格式举例如下，进行地址拼接
    # D:\WORKPLACE\jmeterTest\Version1.0\report\20200110_094242-report\20200110_094242-api1
    # REPORT_PATH + folderName + '\\' + index.html(记得加斜杠分隔符）
    # REPORT_PATH = D:\WORKPLACE\jmeterTest\Version1.0\report\20200110_094242-report\
    # folderName = 20200110_094242-api1

    # 初始化列表主题行内容
    report_td = ''
    # 把报告内文件夹名字设为【date-api】，用-分割
    for folderName in dirs:
        report_td += '<tr>'
        print ("==>>文件夹名称:", folderName)
        # 1)执行时间
        time, apiName = folderName.split ('-')
        print ("==>>>创建时间:", time)
        report_td += '<td>' + time + '</td>'

        # 2)jmx文件
        print ("==>>>api名称:", apiName)
        api_href = "../../api_jmx/" + apiName + '.jmx'
        report_td += '<td><a href="' + api_href + '" target="_blank">' + apiName + '</a></td> '
        print ("==>>api文件地址：", api_href)

        # 3)响应结果jls
        # report_td += '<td><a href="' + RESULT_PATH + time + '-' + apiName + '_result.jsl"
        # target="_blank">' + time + apiName + '_result.jsl</a></td>'
        result_href = "../../result/" + begin_time + 'result/' + time + '-' + apiName + '_result.jsl'
        report_td += '<td><a href="' + result_href + '" target="_blank">' + apiName + '_result.jsl</a></td> '
        print ("==>>jsl文件地址：", result_href)

        # 4)报告详情
        report_href = '../' + begin_time + 'report/' + folderName + '/index.html'
        report_td += '<td><a href="' + report_href + '" target="_blank">查看</a></td>'
        print ("==>>index.html文件地址：", report_href)
        report_td += "</tr>"

    print ("报告汇总在本次生成报告文件夹下面：", REPORT_PATH + begin + 'SummaryReport.html')
    htmlDemo = open (htmlFile, 'w')  # w-覆盖写，a-末尾追加写
    htmlDemo.write (head + th_str + report_td + end)
    htmlDemo.close ()


# 执行主入口
if __name__ == '__main__':
    # 〇、检查路径是否存在（不存在则新增）
    checkPath (JMX_API_PATH)
    checkPath (REPORT_PATH)
    checkPath (RESULT_PATH)

    # 一、读配置文件settings.ini
    cf = configparser.ConfigParser ()
    cf.read (CURRENT_PATH + '/' + settingsFile, encoding='UTF-8')
    print("线程配置文件地址：", CURRENT_PATH + '/' + settingsFile)
    print ("===============读取配置文件1完毕================")

    # 1.线程配置内容(read int)
    number_of_threads = cf.getint ("common_set", "number_of_threads")
    ramp_up_period = cf.getint ("common_set", "ramp_up_period")
    loop_count = cf.getint ("common_set", "loop_count")
    print ("===============获取线程配置完毕================")

    # 2.接口数据地址
    api_path = cf.get ("api_path", "api_data")
    print ('api详情文件名：', api_path)

    # 二、读取api配置详情
    api_cf = configparser.ConfigParser ()
    api_cf.read (CURRENT_PATH + "/" + api_path)
    print("api配置文件目录:", CURRENT_PATH + "/" + api_path)
    print ("===============读取api数据配置文件完毕================")

    # 获取每行api详情
    for item in api_cf["api_test"]:
        api_data = api_cf.get ("api_test", item)
        apiname, ip, port, path, data = splitData (api_data)
        # 三、编辑JMX文件
        jmxName = CURRENT_PATH + '/api_demo.jmx'
        editJMX (jmxName, apiname, ip, port, path, data, loop_count, number_of_threads, ramp_up_period)
        x += 1
    print("=================生成各api接口的jmx文件完毕=====================")
    # 四、执行JMX
    excuteJMX (JMX_API_PATH)
    print("===============执行完毕================")

    # 五、生成报告汇总html
    print ("报告汇总地址：", REPORT_PATH + begin + 'SummaryReport.html')
    createHtml (REPORT_PATH + begin + 'SummaryReport.html', begin)
    print("=============报告生成完毕，程序执行结束===============")
